<?php


namespace app\cms\community\lib\saas;


use app\cms\dto\saas\saasClientInfo;
use app\cms\model\saas\saasClientDbModel;
use app\cms\model\saas\saasClientModel;
use app\cms\model\saas\saasClientServerDbModel;
use app\cms\model\saas\saasClientServerModel;
use iflow\exception\Adapter\HttpException;
use iflow\Response;
use think\db\ConnectionInterface;
use think\facade\Db;

class initializationSaas
{
    // 数据库名称
    protected string $dbName;
    // 数据库用户名
    protected string $dbUser;
    // 数据库密码
    protected string $dbPassword;

    protected array $server = [];
    protected array $dbServer = [];

    protected ConnectionInterface $db;

    public function __construct(int $dbServerId, int $serverId, protected bool $isUpdate = false) {
        $config = config('database');
        $config['connections']['temp'] = $config['connections']['mysql'];

        // 获取数据库服务地址
        $this->dbServer = (new saasClientServerDbModel())->getInfoById($dbServerId);
        if (!$this->dbServer) throw new HttpException(401, '当前未找到数据库服务，请重新选择');

        // 获取服务器地址
        $this->server = (new saasClientServerModel())->getInfoById($serverId);
        if (intval($this->server['status']) !== 1) throw new HttpException(401, '所选服务不可用');

        $config['connections']['temp'] = array_merge([
            // 服务器地址
            'hostname' => $this->dbServer['server_db_ip'],
            // 数据库名
            'database' => $this->dbServer['server_db_name'],
            // 用户名
            'username' => $this->dbServer['server_db_user'],
            // 密码
            'password' => $this->dbServer['server_db_password'],
            // 端口
            'hostport' => $this->dbServer['server_db_port'],
            // 数据库类型
            'type'     => $this->dbServer['server_db_type']
        ], $config['connections']['temp']);
        Db::setConfig($config);
        $this->db = Db::connect('temp');
    }

    // 初始化数据库
    public function initialization(saasClientInfo $saasClientInfo): Response
    {

        $this->dbName = $saasClientInfo -> db_name;
        $this->dbUser = $saasClientInfo -> db_user;
        $this->dbPassword = $saasClientInfo -> db_password;

        // 创建服务时
        if (!$this->isUpdate) {
            // 验证数据库账户是否存在
            $userExists = $this->db -> query("select * from mysql.user where user=:username", [
                'username' => $this->dbUser
            ]);

            if (count($userExists) > 0) {
                throw new HttpException(401, "数据库账户 {$this -> dbUser} 已存在");
            }

            // 创建数据库
            $this->createDatabase();
            load_sql_save_to_server($this->db, app()->getRootPath() . 'install/database/lib');
        }
        // 将Saas服务配置写入数据库
        return $this->saveToSaasClient($saasClientInfo);
    }

    /**
     * 创建数据库
     */
    protected function createDatabase()
    {
        try {
            $dbInfo = $this -> db -> query('select * from information_schema.SCHEMATA where SCHEMA_NAME=:name', ['name' => $this->dbName]);
            if (count($dbInfo) > 0) throw new HttpException(401, '数据库已存在');
            $this -> db -> execute("create database `{$this -> dbUser}`");

            // 创建新的mysql账户并授权
            $this->db -> execute("CREATE USER '{$this -> dbUser}'@'%' IDENTIFIED BY '{$this -> dbPassword}'");
            $this->db -> execute("GRANT ALL ON {$this -> dbName}.* TO '{$this -> dbUser}'@'%'");
            $this->db -> execute("flush privileges");

            // 切换至用户表
            $this->db -> execute("use {$this -> dbName}");
        } catch (\PDOException) {
            throw new HttpException(402, '创建数据库失败');
        }
    }

    /**
     * 保存数据
     * @param saasClientInfo $saasClientInfo
     * @return Response
     */
    protected function saveToSaasClient(saasClientInfo $saasClientInfo): Response
    {
        // 创建账户信息
        $saasModel = new saasClientModel();
        $saasDb = new saasClientDbModel();
        $save = !$this->isUpdate
            ? $saasModel -> saveSaasClient($saasClientInfo)
            : $saasModel -> updateSaasClient($saasClientInfo);

        $saasDbInfo = [
            'db_ip' => $this->dbServer['server_db_ip'],
            'db_port' => $this->dbServer['server_db_port'],
            'type' => $this->dbServer['server_db_type'],
            'db_user' => $this->dbUser,
            'db_name' => $this->dbName,
            'db_password' => $this->dbPassword
        ];

        // 设置 nginx服务配置
        if ($save -> data['code'] === 200) {

            if ($this->isUpdate) {
                $saasDb -> updateSaasClientDb($saasClientInfo -> saas_id, $saasClientInfo -> getUid(), $saasDbInfo);
            } else {
                $saasDbInfo['saas_id'] = $save -> data['items']['id'];
                $saasDbInfo['uid'] = $saasClientInfo -> getUid();
                $saasDb -> createData($saasDbInfo);
            }

            $buildConfig = new buildNginxConfig();
            $buildConfig
                -> setServerName($saasClientInfo -> saas_domain)
                -> setSsl($saasClientInfo -> ssl)
                -> setServerIp($this->server['server_ip'])
                -> setServerPort($this->server['server_port'])
                -> buildConf();

            $params = [
                'nginxConfig' => $buildConfig -> getConfig(),
                'ssl' => $saasClientInfo -> ssl,
                'domain' => $saasClientInfo -> saas_domain
            ];

            // 重启指定服务器
            rpc($this->server['server_name'], 'rpc/saas/account/reload_nginx_server', $params);
        }

        return $save;
    }
}